#ifndef __VECTOR_H__
#define __VECTOR_H__

#include <cmath>
#include <xmmintrin.h>
#include <emmintrin.h>

using namespace std;

namespace math_m{
	template <class Type>
	class Vector2D{
		private:
			Type x;
			Type y;
		public:
			Vector2D(){ x = 0.0; y = 0.0; };
			Vector2D(const Type & _x,const Type & _y){
				x = _x;
				y = _y;
			};
			Vector2D(const Vector2D<Type> & vector){
				x = vector._x();
				y = vector._y();
			};

			Type _x() const{ return x;};
			Type _y() const{ return y;};
			Type value() const{ return sqrt(x*x+y*y);};
			Vector2D<Type> normalize() const{
				Vector2D<Type> _t(x/value(),y/value());
				return _t;
			};
			Vector2D<Type> operator + (const Vector2D<Type> & vector) const{
				Vector2D<Type> _t(x+vector._x(),y+vector._y());
				return _t;
			};
			Vector2D<Type> operator - (const Vector2D<Type> & vector) const{
				Vector2D<Type> _t(x-vector._x(),y-vector._y());
				return _t;
			};
			Vector2D<Type> operator * (const Type & value) const{
				Vector2D<Type> _t(x*value,y*value);
				return _t;
			};
			Type operator * (const Vector2D<Type> & vector) const{
				return x*vector._x()+y*vector._y();
			};
			void operator += (const Vector2D<Type> & vector){
				*this=*this+vector;
			};
			void operator -= (const Vector2D<Type> & vector){
				*this=*this-vector;
			};
			void operator *= (const Type & value){
				*this=*this*value;
			};
			void operator = (const Vector2D<Type> & vector){
				x = vector._x();
				y = vector._y();
			};

			~Vector2D(){ };
	};

	template <class Type>
	class Vector3D{
		private:
			Type x;
			Type y;
			Type z;
		public:
			Vector3D(){
				x = 0.0;
				y = 0.0;
				z = 0.0;
			};
			Vector3D(const Type & _x,
				 const Type & _y,
				 const Type & _z){
				x = _x;
				y = _y;
				z = _z;
			};
			Vector3D(const Vector3D<Type> & vector){
				x = vector._x();
				y = vector._y();
				z = vector._z();
			};

			Type _x() const{ return x;};
			Type _y() const{ return y;};
			Type _z() const{ return z;};
			Type value() const{
				return sqrt(x*x+y*y+z*z);
			};
			Vector3D normalize() const{
				Vector3D<Type> _t(x/value(),
								  y/value(),
								  z/value());
				return _t;
			};

			Vector3D<Type> operator + (const Vector3D<Type> & vector) const{
				Vector3D<Type> _t(x+vector._x(),
								  y+vector._y(),
								  z+vector._z());
				return _t;
			};
			Vector3D<Type> operator - (const Vector3D<Type> & vector){
				Vector3D<Type> _t(x-vector._x(),
								  y-vector._y(),
								  z-vector._z());
				return _t;
			};
			Vector3D<Type> operator * (const Type & value) const{
				Vector3D<Type> _t(x*value,
								  y*value,
								  z*value);
				return _t;
			};
			Type operator * (const Vector3D<Type> & vector) const{
				return x*vector._x()+vector._y()+vector._z();
			};
			Vector3D<Type> operator ^(const Vector3D<Type> & vector) const{
				Vector3D<Type> _t(y*vector._z()-z*vector._y(),
						  z*vector._x()-x*vector._z(),
						  x*vector._y()-y*vector._x());
				return _t;
			};
			void operator += (const Vector3D<Type> & vector){
				*this=*this+vector;
			};
			void operator -= (const Vector3D<Type> & vector){
				*this=*this-vector;
			};
			void operator *= (const Vector3D<Type> & vector){
				*this=*this*vector;
			};
			void operator *= (const Type & value){
				*this=*this*value;
			};
			void operator ^= (const Vector3D<Type> & vector){
				*this=*this^value;
			};
			void operator = (const Vector3D<Type> & vector){
				x = vector._x();
				y = vector._y();
				z = vector._z();
			};

			~Vector3D(){ };
	};

	class Vector2D__m128{
		private:
			__m128 x;
			__m128 y;
		public:
			Vector2D__m128();
			Vector2D__m128(const __m128 & _x,const __m128 & _y);
			Vector2D__m128(const Vector2D__m128 & vector);

			__m128 _x() const;
			__m128 _y() const;
			__m128 value() const;
			Vector2D__m128 normalize() const;

			Vector2D__m128 operator + (const Vector2D__m128 & vector) const;
			Vector2D__m128 operator - (const Vector2D__m128 & vector) const;
			__m128 operator * (const Vector2D__m128 & vector) const;
			Vector2D__m128 operator * (const __m128 & value) const;
			void operator += (const Vector2D__m128 & vector);
			void operator -= (const Vector2D__m128 & vector);
			void operator *= (const __m128 & value);
			void operator = (const Vector2D__m128 & vector);

			~Vector2D__m128();
	};
	class Vector2D__m128d{
		private:
			__m128d x;
			__m128d y;
		public:
			Vector2D__m128d();
			Vector2D__m128d(const __m128d & _x,const __m128d & _y);
			Vector2D__m128d(const Vector2D__m128d & vector);

			__m128d _x() const;
			__m128d _y() const;
			__m128d value() const;
			Vector2D__m128d normalize() const;

			Vector2D__m128d operator + (const Vector2D__m128d & vector) const;
			Vector2D__m128d operator - (const Vector2D__m128d & vector) const;
			__m128d operator * (const Vector2D__m128d & vector) const;
			Vector2D__m128d operator * (const __m128d & value) const;
			void operator += (const Vector2D__m128d & vector);
			void operator -= (const Vector2D__m128d & vector);
			void operator *= (const __m128d & value);
			void operator = (const Vector2D__m128d & vector);
			~Vector2D__m128d();
	};
	class Vector3D__m128{
		private:
			__m128 x;
			__m128 y;
			__m128 z;
		public:
			Vector3D__m128();
			Vector3D__m128(const __m128 & _x,const __m128 & _y,const __m128 & _z);
			Vector3D__m128(const Vector3D__m128 & vector);

			__m128 _x() const;
			__m128 _y() const;
			__m128 _z() const;
			__m128 value() const;
			Vector3D__m128 normalize() const;

			Vector3D__m128 operator + (const Vector3D__m128 & vector) const;
			Vector3D__m128 operator - (const Vector3D__m128 & vector) const;
			Vector3D__m128 operator * (const __m128 & value) const;
			__m128 operator * (const Vector3D__m128 & vector) const;
			Vector3D__m128 operator ^ (const Vector3D__m128 & vector) const;
			void operator += (const Vector3D__m128 & vector);
			void operator -= (const Vector3D__m128 & vector);
			void operator *= (const __m128 & value);
			void operator ^= (const Vector3D__m128 & vector);
			void operator = (const Vector3D__m128 & vector);
			~Vector3D__m128();
	};
}
#endif //__VECTOR_H__
